package com.whf.android.jar.net;

import androidx.annotation.NonNull;

import com.whf.android.jar.app.ConfigKeys;
import com.whf.android.jar.app.Latte;
import com.whf.android.jar.net.rx.RxRestService;
import com.whf.android.jar.util.log.LatteLogger;
import com.whf.android.jar.util.x509.MyX509TrustManager;
import com.whf.android.jar.util.x509.SSLConfigUtils;

import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * 构建OkHttp
 *
 * @author 傅令杰
 * @version 2.0.5
 */

public final class RestCreator {

    /**
     * 构建OkHttp
     */
    private static final class OkHttpHolder {
        private static final OkHttpClient.Builder BUILDER = new OkHttpClient.Builder();
        private static final ArrayList<Interceptor> INTERCEPTORS = Latte.getConfiguration(ConfigKeys.INTERCEPTOR);

        private static OkHttpClient.Builder addInterceptor() {
            if (INTERCEPTORS != null && !INTERCEPTORS.isEmpty()) {
                for (Interceptor interceptor : INTERCEPTORS) {
                    BUILDER.addInterceptor(interceptor);
                }
            }
            return BUILDER;
        }

        private static final OkHttpClient OK_HTTP_CLIENT = addInterceptor()
                // 整个网络最多使用时间 (当你的应用内需要限定 App 在某个指定的时间内得到响应结果，如果在指定时间内未能得到就认为是超时的话)。
                .callTimeout(Latte.getTimeOutCall(), TimeUnit.MINUTES)

                // 连接网络（如果 Retrofit 在指定的时间内无法与服务器端建立连接，那么 Retrofit 就认为这次请求失败）
                .connectTimeout(Latte.getTimeOut(), TimeUnit.MINUTES)

                // 写入超时(注意这个并不是说在指定的时间（比如 15 秒）内需要把所有的数据都发送到服务器端，而是指相邻的两个字节之间的发送时间不能超过指定的时间（15 秒）。
                .writeTimeout(15, TimeUnit.SECONDS)

                // 读取超时(注意这个并不是说在指定的时间（比如 30 秒）内需要把响应内容完全接收，而是指相邻的两个字节之间的接收时间不能超过指定的时间（ 30 秒）)
                .readTimeout(30, TimeUnit.SECONDS)
                .build();

        /**
         * 文件的服务，不设置其他状态。
         */
        private static final OkHttpClient OK_HTTP_DOWNLOAD_CLIENT = new OkHttpClient.Builder()
                //默认值为 0 代表不考虑请求的超时。
                .callTimeout(0, TimeUnit.MINUTES)

                // 连接网络（如果 Retrofit 在指定的时间内无法与服务器端建立连接，那么 Retrofit 就认为这次请求失败）
                .connectTimeout(Latte.getTimeOut(), TimeUnit.MINUTES)

                // 写入超时(注意这个并不是说在指定的时间（比如 15 秒）内需要把所有的数据都发送到服务器端，而是指相邻的两个字节之间的发送时间不能超过指定的时间（15 秒）。
                .writeTimeout(15, TimeUnit.SECONDS)

                // 读取超时(注意这个并不是说在指定的时间（比如 30 秒）内需要把响应内容完全接收，而是指相邻的两个字节之间的接收时间不能超过指定的时间（ 30 秒）)
                .readTimeout(30, TimeUnit.SECONDS)
                .build();

        /**
         * 不安全的解决方案
         */
        @NonNull
        private static OkHttpClient getUnsafeOkHttpClient() {
            final boolean TRUST_CERTIFICATE = Latte.isTrustCertificate();
            if (TRUST_CERTIFICATE) {
                LatteLogger.i("ssl证书监管");
                return OK_HTTP_CLIENT;
            }
            try {
                LatteLogger.i("不安全的解决方案(信任所以证书，不监管)");
                return addInterceptor()
                        // 整个网络最多使用时间 (当你的应用内需要限定 App 在某个指定的时间内得到响应结果，如果在指定时间内未能得到就认为是超时的话)。
                        .callTimeout(Latte.getTimeOutCall(), TimeUnit.MINUTES)

                        // 连接网络（如果 Retrofit 在指定的时间内无法与服务器端建立连接，那么 Retrofit 就认为这次请求失败）
                        .connectTimeout(Latte.getTimeOut(), TimeUnit.MINUTES)

                        // 写入超时(注意这个并不是说在指定的时间（比如 15 秒）内需要把所有的数据都发送到服务器端，而是指相邻的两个字节之间的发送时间不能超过指定的时间（15 秒）。
                        .writeTimeout(15, TimeUnit.SECONDS)

                        // 读取超时(注意这个并不是说在指定的时间（比如 30 秒）内需要把响应内容完全接收，而是指相邻的两个字节之间的接收时间不能超过指定的时间（ 30 秒）)
                        .readTimeout(30, TimeUnit.SECONDS)

                        .sslSocketFactory(SSLConfigUtils.sslSocketFactory(), new MyX509TrustManager())

                        .hostnameVerifier(SSLConfigUtils.hostnameVerifier())

                        .build();
            } catch (Exception e) {
                LatteLogger.e(e.getMessage());
                return OK_HTTP_CLIENT;
            }
        }
    }

    /**
     * 构建全局Retrofit客户端
     */
    private static final class RetrofitHolder {
        private static final String BASE_URL = Latte.getServer();
        private static final Retrofit RETROFIT_CLIENT = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(OkHttpHolder.getUnsafeOkHttpClient())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        private static final Retrofit RETROFIT_DOWNLOAD_CLIENT = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(OkHttpHolder.OK_HTTP_DOWNLOAD_CLIENT)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    /**
     * Service接口
     */
    private static final class RestServiceHolder {
        private static final RestService REST_SERVICE =
                RetrofitHolder.RETROFIT_CLIENT.create(RestService.class);
    }

    static RestService getRestService() {
        return RestServiceHolder.REST_SERVICE;
    }

    /**
     * Service接口
     */
    private static final class RxRestServiceHolder {
        private static final RxRestService REST_SERVICE =
                RetrofitHolder.RETROFIT_CLIENT.create(RxRestService.class);
    }

    public static RxRestService getRxRestService() {
        return RxRestServiceHolder.REST_SERVICE;
    }

    /**
     * Service接口
     */
    private static final class RestDownloadServiceHolder {
        private static final RestService REST_DOWNLOAD_SERVICE =
                RetrofitHolder.RETROFIT_DOWNLOAD_CLIENT.create(RestService.class);
    }

    public static RestService getDownloadRestService() {
        return RestDownloadServiceHolder.REST_DOWNLOAD_SERVICE;
    }

}
